home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C++ / Frameworks / Sprocket Framework DR2 / Sprocket Framework / Window.cp < prev   
Text File  |  1996-06-15  |  24KB  |  999 lines

  1. /*
  2.  
  3.     File:        Window.cp
  4.     Project:    Sprocket Framework 1.1 (DR2), released 6/15/96
  5.     Contains:    Base class which support all aspects of an on-screen window
  6.     To Do:        Make sure invisible windows can be created & managed
  7.                 Fix activate bugs when showing and hiding windows
  8.                 Window positioning methods (getters and setters)
  9.                 Changes to support AEObject model
  10.  
  11.     Sprocket Major Contributors:
  12.     ----------------------------
  13.     Dave Falkenburg, producer of Sprocket 1.0
  14.     Bill Hayden,     producer of Sprocket 1.1
  15.     Steve Sisak,     producer of the upcoming Sprocket 2.0
  16.     
  17.     Pete Alexander        Steve Falkenburg    Randy Thelen
  18.     Eric Berdahl        Nitin Ganatra        Chris K. Thomas
  19.     Marshall Clow        Dave Hershey        Leonard Rosenthal
  20.     Tim Craycroft        Dave Mark            Dean Yu
  21.     David denBoer        Gary Powell
  22.     Cameron Esfahani    Jon Summers            Apple Computer, Inc.
  23.         
  24.     Comments, Additions, or Corrections:
  25.     ------------------------------------
  26.     Bill Hayden, Nikol Software <nikol@codewell.com>
  27.  
  28. */
  29.  
  30.  
  31. #include "Sprocket.h"
  32. #include "Window.h"
  33.  
  34.  
  35. RgnHandle    TWindow::fgScratchRgn = nil;
  36. short        TWindow::fgNumWindows = 0;
  37.  
  38.  
  39. const short            kFloatingWindowKind        = 1000;
  40. const short            kNormalWindowKind        = 1001;
  41. const WindowRef     kNoFloatingWindows        = (WindowRef) -1;
  42.  
  43. const short            kScreenEdgeSlop            = 4;
  44. const short            kSpaceForFinderIcons    = 64;
  45. const short            kMinimumTitleBarHeight    = 21;
  46. const short            kMinimumWindowSize        = 32;
  47.  
  48. static void            HiliteShowHideFloatingWindows(Boolean hiliting,Boolean hiding);
  49.  
  50. static void            FindScreenRectWithLargestPartOfWindow(WindowRef aWindow,Rect *theBestScreenRect, GDHandle * theBestDevice);
  51. static pascal void    CalculateWindowAreaOnDevice(short depth,short deviceFlags,GDHandle targetDevice,long userData);
  52.  
  53. struct    CalcWindowAreaDeviceLoopUserData
  54.     {
  55.     GDHandle    fScreenWithLargestPartOfWindow;
  56.     long        fLargestArea;
  57.     Rect        fWindowBounds;
  58.     };
  59.  
  60.  
  61.  
  62.  
  63.  
  64. TWindow::TWindow()
  65. {
  66.     fIsDialogWindow = false;
  67.  
  68.     if (fgScratchRgn == nil)
  69.         fgScratchRgn = NewRgn();
  70.  
  71.     fgNumWindows++;
  72. }
  73.  
  74.  
  75. TWindow::~TWindow()
  76. {
  77.     if ((--fgNumWindows <= 0) && (fgScratchRgn != nil))
  78.         {
  79.         DisposeRgn(fgScratchRgn);
  80.         fgScratchRgn = nil;
  81.         }
  82. }
  83.  
  84.  
  85. void TWindow::CreateWindow(WindowType typeOfWindowToCreate /* = kNormalWindow */)
  86. {
  87.     WindowRef    behindWindow, oldFrontMostWindow;
  88.     
  89.     if (typeOfWindowToCreate == kModalWindow)
  90.         {
  91.         behindWindow = (WindowRef) -1;
  92.         oldFrontMostWindow = FrontWindow();
  93.  
  94.         fWindowType = kModalWindow;
  95.         }
  96.     else if (typeOfWindowToCreate == kFloatingWindow)
  97.         {
  98.         behindWindow = (WindowRef) -1;
  99.         oldFrontMostWindow = FrontWindow();
  100.  
  101.         fWindowType = kFloatingWindow;
  102.         }
  103.     else if (typeOfWindowToCreate == kNormalWindow)
  104.         {
  105.         behindWindow = LastFloatingWindow();
  106.  
  107.         fWindowType = kNormalWindow;
  108.         
  109.         if (behindWindow == kNoFloatingWindows)
  110.             oldFrontMostWindow = FrontNonFloatingWindow();    // •••
  111.         else
  112.             oldFrontMostWindow = GetNextWindow ( behindWindow );
  113.         }
  114.  
  115.     fWindow = this->MakeNewWindow(behindWindow);
  116.     fIsVisible = IsWindowVisible ( fWindow );
  117.  
  118.     if (fWindow)
  119.         {
  120.         SetWRefCon(fWindow,(long) this);
  121.  
  122.         if (typeOfWindowToCreate == kModalWindow)
  123.             {
  124.             SetWindowKind ( fWindow, kNormalWindowKind );
  125.             
  126.             HiliteAndActivateWindow(fWindow,true);
  127.             
  128.             HiliteWindowsForModalDialog(false);
  129.             ShowWindow(fWindow);
  130.             HiliteAndActivateWindow(fWindow,true);
  131.             }
  132.         else if (typeOfWindowToCreate == kFloatingWindow)
  133.             {
  134.             SetWindowKind ( fWindow, kFloatingWindowKind );
  135.             
  136.             //    make sure the other window stays hilited
  137.             if (oldFrontMostWindow)
  138.                 HiliteAndActivateWindow(oldFrontMostWindow,true);
  139.             }
  140.         else if (typeOfWindowToCreate == kNormalWindow)
  141.             {
  142.             SetWindowKind ( fWindow, kNormalWindowKind );
  143.  
  144.             //    unhighlight the old front window
  145.             if (oldFrontMostWindow)
  146.                 HiliteAndActivateWindow(oldFrontMostWindow,false);
  147.  
  148.             //    hilite the new window…
  149.             HiliteAndActivateWindow(fWindow,true);
  150.             }
  151.         }
  152. }
  153.  
  154.  
  155. void
  156. TWindow::AdjustCursor(EventRecord * /* anEvent */)
  157. {
  158. }
  159.  
  160. void
  161. TWindow::Idle(EventRecord * /* anEvent */)
  162. {
  163. }
  164.     
  165. void
  166. TWindow::Activate(Boolean /* activating */)
  167. {
  168. }
  169.     
  170. void
  171. TWindow::Draw(void)
  172. {
  173. }
  174.     
  175. void
  176. TWindow::Click(EventRecord * /* anEvent */)
  177. {
  178.     this->Select();
  179. }
  180.     
  181. void
  182. TWindow::KeyDown(EventRecord * /* anEvent */)
  183. {
  184. }
  185.  
  186.  
  187. Boolean TWindow::Select(void)
  188. {
  189.     WindowRef    currentFrontWindow;
  190.     
  191.     if (fWindowType == kNormalWindow)
  192.         currentFrontWindow = FrontNonFloatingWindow();
  193.     else
  194.         currentFrontWindow = FrontWindow();
  195.     
  196.     if (currentFrontWindow != fWindow)
  197.         {
  198.         TWindow*    front = GetWindowObject(currentFrontWindow);
  199.         
  200.         if (front->fWindowType == kModalWindow)
  201.             {
  202.             SysBeep(1);
  203.             return false;    // window is not a legal destination for clicks
  204.             }
  205.         else if (fWindowType == kFloatingWindow)
  206.             BringToFront( fWindow );
  207.         else
  208.             {
  209.             WindowRef    lastFloater = LastFloatingWindow();
  210.  
  211.             // Deactivate the window currently in front.
  212.  
  213.             HiliteAndActivateWindow(currentFrontWindow, false);
  214.  
  215.             if (lastFloater == kNoFloatingWindows)
  216.                 {
  217.                 //    If there are no floating windows,
  218.                 //    just call SelectWindow like the good ol’ days
  219.  
  220.                 SelectWindow(fWindow);
  221.                 }
  222.             else
  223.                 {
  224.                 // Bring it behind the last floating window and activate it.
  225.                 // Note that Inside Mac 1 states that you need to call PaintOne() and CalcVis() on a
  226.                 // window if you are using SendBehind() to bring it closer to the front.  With System 7,
  227.                 // this is no longer necessary.
  228.  
  229.                 SendBehind( fWindow, lastFloater);
  230.                 }
  231.  
  232.             //    Hilite the new front window
  233.  
  234.             HiliteAndActivateWindow(fWindow,true);
  235.             }
  236.         }
  237.  
  238.     return true;        // window is a legal destination for clicks
  239. }
  240.  
  241.  
  242. void TWindow::Drag(Point startPoint)
  243.     {
  244.     GrafPtr        savePort;
  245.     KeyMap        theKeyMap;
  246.     Boolean        commandKeyDown = false;
  247.     long        dragResult;
  248.     WindowRef    currentFrontWindow;
  249.  
  250.     if (fWindowType == kNormalWindow)
  251.         currentFrontWindow = FrontNonFloatingWindow();
  252.     else
  253.         currentFrontWindow = FrontWindow();
  254.     
  255.     if (currentFrontWindow != fWindow)
  256.         {
  257.         TWindow*    front = GetWindowObject(currentFrontWindow);
  258.         
  259.         if (front->fWindowType == kModalWindow)
  260.             {
  261.             SysBeep(1);
  262.             return;    // window is not a legal drag
  263.             }
  264.         }
  265.     
  266.     if (WaitMouseUp())        //    de-bounce?
  267.         {
  268.         // Set up the Window Manager port.
  269.     
  270.         GetPort(&savePort);
  271.         SetPort(gWindowManagerPort);
  272.         SetClip(GetGrayRgn());
  273.  
  274.         // Check to see if the command key is down.
  275.     
  276.         GetKeys(theKeyMap);
  277.         commandKeyDown = ((theKeyMap[1] & 0x8000) != 0);
  278.         
  279.         if (commandKeyDown)
  280.             {
  281.             //    We’re not going to change window ordering,
  282.             //    so make sure that we don’t drag in front of
  283.             //    other windows which may be in front of ours.
  284.  
  285.             ClipAbove(fWindow);
  286.             }
  287.         else if (fWindowType != kFloatingWindow)
  288.             {
  289.             //    We’re dragging a normal window, so make sure
  290.             //    that we don’t drag in front of any floating
  291.             //    windows.
  292.  
  293.             ClipAbove(FrontNonFloatingWindow());
  294.             }
  295.         
  296.         //    Drag an outline of the window around the desktop.
  297.         //    NOTE: DragGrayRgn destroys the region passed in, so make a copy
  298.  
  299.         GetWindowStructureRgn(fWindow, fgScratchRgn);
  300.         dragResult = DragGrayRgn(fgScratchRgn, startPoint, &gDeskRectangle, &gDeskRectangle, noConstraint, nil);
  301.     
  302.         SetPort(savePort);    //    Get back to old port
  303.  
  304.         if ((dragResult != 0) && (dragResult != 0x80008000))
  305.             {
  306.             this->Nudge((short) (dragResult & 0xFFFF),(short) (dragResult >> 16));
  307.             }
  308.         }
  309.  
  310.     if (!commandKeyDown)
  311.         Select();
  312. }
  313.  
  314.  
  315.  
  316. void TWindow::Nudge(short horizontalDistance, short verticalDistance)
  317. {
  318.     short        newHorizontalPosition, newVerticalPosition;
  319.     RgnHandle    tempRgn = NewRgn ();
  320.  
  321.     GetWindowContentRgn ( fWindow, tempRgn );
  322.     newHorizontalPosition = (short) (**tempRgn).rgnBBox.left + horizontalDistance;
  323.     newVerticalPosition   = (short) (**tempRgn).rgnBBox.top  + verticalDistance;
  324.     DisposeRgn ( tempRgn );
  325.  
  326.     ::MoveWindow(fWindow, newHorizontalPosition, newVerticalPosition, false);
  327. }
  328.  
  329.  
  330.  
  331. void TWindow::Grow(Point startPoint)
  332. {
  333.     GrafPtr    oldPort;
  334.     long    newSize;
  335.     Rect    oldWindowRect,resizeLimits;
  336.     
  337.     GetPort(&oldPort);
  338.     
  339.     GetWindowSizeLimits(&resizeLimits);
  340.     newSize = GrowWindow(fWindow,startPoint, &resizeLimits);
  341.     if (newSize)
  342.         {
  343.         oldWindowRect = GetWindowPort ( fWindow )->portRect;
  344.         SizeWindow ( fWindow, (short) newSize, (short) (newSize >> 16), true );
  345.         SetPortWindowPort ( fWindow );
  346.         resizeLimits = GetWindowPort ( fWindow )->portRect;
  347.         this->AdjustForNewWindowSize(&oldWindowRect, &resizeLimits);
  348.         }
  349.     
  350.     SetPort(oldPort);
  351. }
  352.  
  353.  
  354. void TWindow::Zoom(short zoomState)
  355. {
  356.     GrafPtr        oldPort;
  357.     FontInfo    systemFontInfo;
  358.     short        titleBarHeight;
  359.     Rect        bestScreenRect,perfectWindowRect,scratchRect;
  360.     short        amountOffscreen;
  361. //    WindowPeek    windowAsWindowPeek = (WindowPeek) fWindow;
  362.     GDHandle    bestDevice;
  363.     
  364.     GetPort(&oldPort);
  365.  
  366.     //    Figure out the height of the title bar so we can properly position
  367.     //    a window. The algorithm is stolen from the System 7.x 'WDEF' (0)
  368.     //
  369.     //    This probably isn’t the best thing to do: A better way might be 
  370.     //    to diff the structure and content region rectangles?
  371.  
  372.     SetPort(gWindowManagerPort);
  373.     GetFontInfo(&systemFontInfo);
  374.     titleBarHeight = (short) (systemFontInfo.ascent + systemFontInfo.descent + 4);
  375.     if ((titleBarHeight % 2) == 1)
  376.         titleBarHeight--;
  377.     if (titleBarHeight < kMinimumTitleBarHeight)
  378.         titleBarHeight = kMinimumTitleBarHeight;
  379.  
  380.  
  381.     //    Only do the voodoo magic if we are really “zooming” the window.
  382.  
  383.     if (zoomState == inZoomOut)
  384.         {
  385.         FindScreenRectWithLargestPartOfWindow(fWindow,&bestScreenRect,&bestDevice);
  386.         bestScreenRect.top += titleBarHeight;
  387.  
  388.         this->GetPerfectWindowSize(&perfectWindowRect);
  389.         OffsetRect(&perfectWindowRect,-perfectWindowRect.left,-perfectWindowRect.top);
  390.  
  391.         //    Take the zero-pinned perfect window size and move it to
  392.         //    the top left of the    window’s content region.
  393.  
  394.         RgnHandle    tempRgn = NewRgn ();
  395.         GetWindowContentRgn ( fWindow, tempRgn );
  396.         OffsetRect ( &perfectWindowRect,
  397.                             (**tempRgn).rgnBBox.left, (**tempRgn).rgnBBox.top );
  398.         DisposeRgn ( tempRgn );
  399.  
  400.  
  401.         //    Does perfectWindowRect fit completely on the best screen?
  402.         
  403.         SectRect(&perfectWindowRect, &bestScreenRect, &scratchRect);
  404.         if (!EqualRect(&perfectWindowRect, &scratchRect))
  405.             {
  406.             //    SectRect sez perfectWindowRect doesn’t completely fit
  407.             //    on the screen, so bump the window so that more of it fits.
  408.  
  409.             //    Make sure that the left edge of perfectWindowRect is forced
  410.             //    onto the best screen.  This is in case we are bumping
  411.             //    the window to the right.
  412.  
  413.             amountOffscreen = bestScreenRect.left - perfectWindowRect.left;
  414.             if (amountOffscreen > 0)
  415.                 {
  416.                 perfectWindowRect.left += amountOffscreen;
  417.                 perfectWindowRect.right += amountOffscreen;
  418.                 }
  419.  
  420.             //    Make sure that the left edge of perfectWindowRect is forced
  421.             //    onto the best screen.  This is in case we are bumping
  422.             //    the window downward to a new screen.
  423.     
  424.             amountOffscreen = bestScreenRect.top - perfectWindowRect.top;
  425.             if (amountOffscreen > 0)
  426.                 {
  427.                 perfectWindowRect.top += amountOffscreen;
  428.                 perfectWindowRect.bottom += amountOffscreen;
  429.                 }
  430.  
  431.             //    If right edge of window falls off the screen,
  432.             //        Move window to the left until the right edge IS on the screen
  433.             //        OR the left edge is at bestScreenRect.left
  434.  
  435.             amountOffscreen = perfectWindowRect.right - bestScreenRect.right;
  436.             if (amountOffscreen > 0)
  437.                 {
  438.                 //    Are we going to push the left edge offscreen? If so, change the
  439.                 //    offset so we move the window all the way over to the left.
  440.                 
  441.                 if ((perfectWindowRect.left - amountOffscreen) < bestScreenRect.left)
  442.                     amountOffscreen = perfectWindowRect.left - bestScreenRect.left;
  443.  
  444.                 perfectWindowRect.left -= amountOffscreen;
  445.                 perfectWindowRect.right -= amountOffscreen;
  446.                 }
  447.  
  448.             //    If bottom edge of window falls off the screen,
  449.             //        Move window to up until the bottom edge IS on the screen
  450.             //        OR the top edge is at bestScreenRect.top
  451.  
  452.             amountOffscreen = perfectWindowRect.bottom - bestScreenRect.bottom;
  453.             if (amountOffscreen > 0)
  454.                 {
  455.                 //    Are we going to push the top edge offscreen? If so, change the
  456.                 //    offset so we move the window just to the top.
  457.                 
  458.                 if ((perfectWindowRect.top - amountOffscreen) < bestScreenRect.top)
  459.                     amountOffscreen = perfectWindowRect.top - bestScreenRect.top;
  460.  
  461.                 perfectWindowRect.top -= amountOffscreen;
  462.                 perfectWindowRect.bottom -= amountOffscreen;
  463.                 }
  464.  
  465.             SectRect(&perfectWindowRect, &bestScreenRect, &scratchRect);
  466.             if (!EqualRect(&perfectWindowRect, &scratchRect))
  467.                 {
  468.                 //    The edges of the window still fall offscreen,
  469.                 //    so make the window smaller until it fits.
  470.                 
  471.                 if (perfectWindowRect.bottom > bestScreenRect.bottom)
  472.                     perfectWindowRect.bottom = bestScreenRect.bottom;
  473.  
  474.                 //    If the right edge is still falling off,
  475.                 //        save space for Finder’s disk icons as well.
  476.  
  477.                 if (perfectWindowRect.right > bestScreenRect.right)
  478.                     {
  479.                     perfectWindowRect.right = bestScreenRect.right;
  480.                     
  481.                     //    If we were on the main screen, leave room for Finder icons, too.
  482.                     
  483.                     if (bestDevice == GetMainDevice())
  484.                         perfectWindowRect.right -= kSpaceForFinderIcons;
  485.                     }
  486.                 }
  487.             }
  488.  
  489.         //    Stash our new rectangle inside of the Window’s dataHandle
  490.         //    so that ZoomWindow does the right thing.
  491.         
  492.     //    (**((WStateDataHandle) (windowAsWindowPeek->dataHandle))).stdState = perfectWindowRect;
  493.         SetWindowStandardState ( fWindow, &perfectWindowRect );
  494.         }
  495.  
  496.     //    HEY YOU! Don’t forget to set the port to the window being zoomed
  497.     //    Why, you ask? Because IM-IV-50 says to; otherwise you die
  498.     
  499.     SetPortWindowPort ( fWindow );
  500.  
  501.     Rect    oldWindowRect = GetWindowPort ( fWindow )->portRect;    
  502.     ZoomWindow(fWindow,zoomState,false);
  503.     Rect    newWindowRect = GetWindowPort ( fWindow )->portRect;
  504.     this->AdjustForNewWindowSize(&oldWindowRect,&newWindowRect);
  505.  
  506.     SetPort(oldPort);
  507. }
  508.  
  509.  
  510.  
  511. void TWindow::ShowHide(Boolean showFlag)
  512. {
  513.     //    Here we need the “::” in front of ShowHide to indicate we are calling
  514.     //    the global function, and not the method ShowHide. Unintended recursion
  515.     //    can do bad things to the unsuspecting programmer.
  516.     
  517.     //    Some C++ programmers would always prepend the “::” on function calls.
  518.     
  519.     ::ShowHide(fWindow,showFlag);
  520.     fIsVisible = showFlag;
  521. }
  522.  
  523.  
  524.  
  525. Boolean TWindow::EventFilter(EventRecord * /* theEvent */)
  526. {
  527.     return false;
  528. }
  529.     
  530.  
  531.  
  532. void TWindow::GetPerfectWindowSize(Rect *perfectSize)
  533. {
  534.     *perfectSize = qd.screenBits.bounds;
  535. }
  536.  
  537.  
  538.  
  539. void TWindow::GetWindowSizeLimits(Rect *limits)
  540. {
  541.     limits->top = limits->left = kMinimumWindowSize;
  542.     limits->right = gDeskRectangle.right - gDeskRectangle.left;
  543.     limits->bottom = gDeskRectangle.bottom - gDeskRectangle.top;
  544. }
  545.  
  546.  
  547.  
  548. void TWindow::AdjustForNewWindowSize(Rect * /* oldRect */, Rect * /* newSize */)
  549. {
  550. }
  551.  
  552.  
  553.  
  554. Boolean TWindow::IsVisible(void)
  555. {
  556.     return fIsVisible;
  557. }
  558.  
  559.  
  560.  
  561. Boolean TWindow::CanClose(Boolean /* quitting */)
  562. {
  563.     return true;
  564. }
  565.  
  566.  
  567.  
  568. Boolean TWindow::Close(void)
  569. {
  570.     WindowRef    newFrontWindow = nil;
  571.  
  572.     if (FrontNonFloatingWindow() == fWindow)
  573.         newFrontWindow = GetNextWindow ( fWindow );
  574.  
  575.     this->Activate(false);
  576.  
  577.     if (fIsDialogWindow)
  578.         DisposeDialog((DialogRef) fWindow);
  579.     else
  580.         DisposeWindow(fWindow);
  581.  
  582.     if (fWindowType == kModalWindow)
  583.         HiliteWindowsForModalDialog(true);
  584.  
  585.     if (newFrontWindow)
  586.         HiliteAndActivateWindow(newFrontWindow,true);
  587.  
  588.     return true;
  589. }
  590.  
  591.  
  592. Boolean TWindow::DeleteAfterClose(void)
  593. {
  594.     return true;
  595. }
  596.  
  597.  
  598. void TWindow::AdjustMenusBeforeMenuSelection(void)
  599. {
  600. }
  601.  
  602.     
  603. Boolean TWindow::DoMenuSelection(short /* menu */, short /* item */)
  604. {
  605.     return false;
  606. }
  607.     
  608.  
  609.  
  610. Boolean TWindow::DoCommand(CommandID theCommand)
  611. {
  612.     if (theCommand == cClose)
  613.         {
  614.         if (this->CanClose(false) && this->Close() && this->DeleteAfterClose())
  615.             delete this;
  616.         return true;
  617.         }
  618.  
  619.     return false;
  620. }
  621.  
  622.  
  623. void TWindow::ClickAndDrag(EventRecord * anEvent)
  624. {
  625.     //    By default, we just convert to local coordinates
  626.     //        and call the window’s Click method.
  627.  
  628.     GlobalToLocal(&anEvent->where);
  629.     this->Click(anEvent);
  630. }
  631.  
  632.  
  633. OSErr TWindow::HandleDrag(DragTrackingMessage dragMessage,DragReference theDrag)
  634. {
  635.     OSErr    result = dragNotAcceptedErr;
  636.     
  637.     switch (dragMessage)
  638.         {
  639.         case    dragTrackingEnterWindow:
  640.             result = this->DragEnterWindow(theDrag);
  641.             break;
  642.         
  643.         case    dragTrackingInWindow:
  644.             result = this->DragInWindow(theDrag);
  645.             break;
  646.             
  647.         case    dragTrackingLeaveWindow:
  648.             result = this->DragLeaveWindow(theDrag);
  649.             break;
  650.             
  651.         default:
  652.             break;
  653.         }
  654.  
  655.     return result;
  656. }
  657.  
  658.  
  659. OSErr TWindow::DragEnterWindow(DragReference /* theDrag */)
  660. {
  661.     return dragNotAcceptedErr;
  662. }
  663.  
  664.  
  665. OSErr TWindow::DragInWindow(DragReference /* theDrag */)
  666.     {
  667.     return dragNotAcceptedErr;
  668.     }
  669.  
  670.  
  671. OSErr TWindow::DragLeaveWindow(DragReference /* theDrag */)
  672. {
  673.     return dragNotAcceptedErr;
  674. }
  675.     
  676.  
  677. OSErr TWindow::HandleDrop(DragReference /* theDrag */)
  678. {
  679.     return dragNotAcceptedErr;
  680. }
  681.  
  682.  
  683.  
  684. Boolean    TWindow::IsPointInContentRgn( Point pt )
  685. {
  686.     GetWindowContentRgn(fWindow, fgScratchRgn);
  687.     Boolean result = PtInRgn( pt, fgScratchRgn );
  688.     return result;
  689. }
  690.  
  691.  
  692.  
  693. Boolean    TWindow::IsMouseInContentRgn( DragReference dragRef )
  694. {
  695.     Point    globalMouse;
  696.     OSErr    err;
  697.     
  698.     err = GetDragMouse( dragRef, &globalMouse, 0L );
  699.     
  700.     if ( err == noErr )
  701.         return( this->IsPointInContentRgn( globalMouse ) );
  702.     else
  703.         return( false );
  704. }
  705.  
  706.  
  707.  
  708. Rect TWindow::GetContentsBounds(void)
  709. {
  710.     Rect r;
  711.  
  712.     GetWindowContentRgn(fWindow, fgScratchRgn);
  713.     r = (**fgScratchRgn).rgnBBox;
  714.     return r;
  715. }
  716.  
  717.  
  718.  
  719. ///////////////////////////////////////////////////////////////////////////
  720. //
  721. //    Utility Functions used for floating windows
  722. //
  723.  
  724. TWindow* GetWindowObject(WindowRef aWindow)
  725. {
  726.     short    wKind;
  727.     
  728.     if (aWindow != nil)
  729.         {
  730.         wKind = GetWindowKind ( aWindow );
  731.  
  732.         if (wKind >= userKind)
  733.             {
  734.             //    All windowKinds >= userKind are based upon TWindow
  735.  
  736.             return (TWindow *) GetWRefCon(aWindow);
  737.             }
  738.         }
  739.     return (TWindow *) nil;
  740. }
  741.  
  742.  
  743. ////////////////////////////////////////////////////////////////////////
  744. //
  745. //    Utility functions
  746.  
  747.  
  748. pascal WindowRef
  749. GetNewColorOrBlackAndWhiteWindow(short windowID, void *wStorage, WindowRef behind)
  750.     {
  751.     if (gHasColorQuickdraw)
  752.         return GetNewCWindow(windowID,wStorage,behind);
  753.     else
  754.         return GetNewWindow(windowID,wStorage,behind);
  755.     }
  756.  
  757.  
  758. pascal WindowRef
  759. NewColorOrBlackAndWhiteWindow(void *wStorage, const Rect *boundsRect, ConstStr255Param title, Boolean visible, short theProc, WindowRef behind, Boolean goAwayFlag, long refCon)
  760.     {
  761.     if (gHasColorQuickdraw)
  762.         return NewCWindow(wStorage,boundsRect,title,visible,theProc,behind,goAwayFlag,refCon);
  763.     else
  764.         return NewWindow(wStorage,boundsRect,title,visible,theProc,behind,goAwayFlag,refCon);
  765.     }
  766.  
  767.  
  768.  
  769. void DrawJustTheGrowIcon(WindowRef aWindow)
  770. {
  771.     GrafPtr        savedPort;
  772.     Rect        growBoxRect;
  773.     
  774.     GetPort(&savedPort);
  775.     SetPortWindowPort ( aWindow );
  776.     GetClip(TWindow::fgScratchRgn);
  777.  
  778.     //    clip to just the bottom right corner of the window
  779.     growBoxRect = GetWindowPort ( aWindow )->portRect;
  780.     growBoxRect.top        = growBoxRect.bottom - kScrollbarWidth;
  781.     growBoxRect.left    = growBoxRect.right - kScrollbarWidth;
  782.     ClipRect(&growBoxRect);
  783.  
  784.     if (aWindow == FrontWindow())
  785.         DrawGrowIcon(aWindow);
  786.     else
  787.         {
  788.         InsetRect(&growBoxRect, 2, 2);
  789.         EraseRect(&growBoxRect);
  790.         }
  791.  
  792.     SetClip(TWindow::fgScratchRgn);
  793.     SetPort(savedPort);
  794. }
  795.     
  796.  
  797.  
  798. WindowRef LastFloatingWindow(void)
  799. {
  800.     WindowRef    aWindow        = FrontWindow();
  801.     WindowRef    lastFloater = (WindowRef) kNoFloatingWindows;
  802.     
  803.     while ( aWindow != nil && GetWindowKind ( aWindow ) == kFloatingWindowKind )
  804.         {
  805.         if ( IsWindowVisible ( aWindow ))
  806.             lastFloater = (WindowRef) aWindow;
  807.  
  808.         aWindow = GetNextWindow ( aWindow );
  809.         }
  810.  
  811.     return lastFloater;
  812. }
  813.  
  814.  
  815.  
  816. WindowRef FrontNonFloatingWindow(void)
  817. {
  818.     WindowRef    aWindow = (WindowRef) LMGetWindowList ();
  819.  
  820. //    Skip over floating windows        
  821.     while ( aWindow != nil && GetWindowKind ( aWindow ) == kFloatingWindowKind )
  822.         aWindow = GetNextWindow ( aWindow );
  823.  
  824. //    Skip over invisible, but otherwise normal windows
  825.     while (aWindow != nil && !IsWindowVisible ( aWindow ))
  826.         aWindow = GetNextWindow ( aWindow );
  827.         
  828.     return aWindow;
  829. }
  830.  
  831.  
  832. void HiliteAndActivateWindow(WindowRef aWindow,Boolean active)
  833. {
  834.     GrafPtr        oldPort;
  835.     TWindow    *    wobj = GetWindowObject(aWindow);
  836.     
  837.     if (aWindow)
  838.         {
  839.         HiliteWindow(aWindow,active);
  840.  
  841.         if (wobj != nil)
  842.             {
  843.             GetPort(&oldPort);
  844.             SetPortWindowPort ( aWindow );
  845.             wobj->Activate(active);
  846.             SetPort(oldPort);
  847.             }    
  848.         }
  849. }
  850.  
  851. void SuspendResumeWindows(Boolean resuming)
  852. {
  853.     //    When we suspend/resume, hide/show all the visible floaters
  854.     
  855.     HiliteShowHideFloatingWindows(resuming,true);
  856. }
  857.  
  858. void HiliteWindowsForModalDialog(Boolean hiliting)
  859. {
  860.     //    When we display a modal dialog, we need to unhighlight
  861.     //    all visible floaters. We also need to re-hilite them
  862.     //    afterwards.
  863.     
  864.     HiliteShowHideFloatingWindows(hiliting,false);
  865. }
  866.  
  867. void HiliteShowHideFloatingWindows(Boolean hiliting, Boolean dohiding)
  868. {
  869.     WindowRef    aWindow;
  870.     TWindow *    wobj;
  871.     
  872.     HiliteAndActivateWindow(FrontNonFloatingWindow(), hiliting);
  873.  
  874.     aWindow = (WindowRef) LMGetWindowList();
  875.     while ( aWindow != nil && GetWindowKind ( aWindow ) == kFloatingWindowKind )
  876.         {
  877.         wobj = GetWindowObject ( aWindow );
  878.         
  879.         //    If we are hiding or showing, only hide/show windows
  880.         //    that were visible to begin with.
  881.         
  882.         //    NOTE:    We use our copy of the visible flag so we can
  883.         //            automatically show floaters on a resume event.
  884.         
  885.         //    NOTE:    Since this isn’t a method of TWindow, we don’t
  886.         //            really need the “::” on ShowHide, but as long
  887.         //            as we’re trying to avoid ambiguity.
  888.         
  889.         if (dohiding && (wobj != nil) && (wobj->IsVisible()))
  890.             ::ShowHide(aWindow,hiliting);
  891.             
  892.         //    All floaters are hilited if any floater is hilited
  893.  
  894.         HiliteWindow( aWindow,hiliting);
  895.         aWindow = GetNextWindow ( aWindow );
  896.         }
  897. }
  898.  
  899.  
  900. ///////////////////////////////////////////////////////////////////////////
  901. //
  902. //    Routines used for dealing with windows and multiple screens
  903. //
  904.  
  905. pascal void
  906. CalculateWindowAreaOnDevice(short /* depth */,short /* deviceFlags */,GDHandle targetDevice,long userData)
  907. {
  908.     CalcWindowAreaDeviceLoopUserData *    deviceLoopDataPtr;
  909.     long                                windowAreaOnThisScreen;
  910.     Rect                                windowRectOnThisScreen;
  911.     
  912.     deviceLoopDataPtr = (CalcWindowAreaDeviceLoopUserData *) userData;
  913.  
  914.     SectRect(&deviceLoopDataPtr->fWindowBounds, &(**targetDevice).gdRect,&windowRectOnThisScreen);
  915.     OffsetRect(&windowRectOnThisScreen,-windowRectOnThisScreen.left,-windowRectOnThisScreen.top);
  916.     windowAreaOnThisScreen = windowRectOnThisScreen.right * windowRectOnThisScreen.bottom;
  917.  
  918.     if (windowAreaOnThisScreen > deviceLoopDataPtr->fLargestArea)
  919.         {
  920.         deviceLoopDataPtr->fLargestArea = windowAreaOnThisScreen;
  921.         deviceLoopDataPtr->fScreenWithLargestPartOfWindow = targetDevice;
  922.         }
  923. }
  924.  
  925.  
  926. DeviceLoopDrawingUPP CallCalcWindowAreaOnDevice = NewDeviceLoopDrawingProc(&CalculateWindowAreaOnDevice);
  927.  
  928.  
  929. void
  930. FindScreenRectWithLargestPartOfWindow(WindowRef aWindow,Rect *theBestScreenRect,GDHandle * theBestDevice)
  931. {
  932.     RgnHandle                            copyOfWindowStrucRgn;
  933.     CalcWindowAreaDeviceLoopUserData    deviceLoopData;
  934.  
  935.     //    Use DeviceLoop to find out what GDevice contains the largest
  936.     //    portion of the supplied window.
  937.     //
  938.     //    NOTE:    Assumes thePort == the Window Manager Port because we using
  939.     //            the window strucRgn, not contRgn.
  940.  
  941.     deviceLoopData.fScreenWithLargestPartOfWindow = nil;
  942.     deviceLoopData.fLargestArea = -1;
  943.  
  944.     RgnHandle    tempRgn = NewRgn ();
  945.     GetWindowContentRgn ( aWindow, tempRgn );
  946.     deviceLoopData.fWindowBounds = (**tempRgn).rgnBBox;
  947.     DisposeRgn ( tempRgn );
  948.  
  949.     copyOfWindowStrucRgn = NewRgn();
  950.     GetWindowStructureRgn ( aWindow, copyOfWindowStrucRgn );
  951.  
  952.     DeviceLoop(copyOfWindowStrucRgn,CallCalcWindowAreaOnDevice,(long) &deviceLoopData,singleDevices);    
  953.  
  954.     DisposeRgn(copyOfWindowStrucRgn);
  955.     
  956.     *theBestDevice = deviceLoopData.fScreenWithLargestPartOfWindow;
  957.     *theBestScreenRect = (**(deviceLoopData.fScreenWithLargestPartOfWindow)).gdRect;
  958.  
  959.     //    Leave some space around the edges of the screen so window look good, AND
  960.     //    if the best device is the main screen, leave space for the Menubar
  961.     
  962.     InsetRect(theBestScreenRect,kScreenEdgeSlop,kScreenEdgeSlop);
  963.     if (GetMainDevice() == deviceLoopData.fScreenWithLargestPartOfWindow)
  964.         theBestScreenRect->top += GetMBarHeight();
  965. }
  966.  
  967.  
  968. ///////////////////////////////////////////////////////////////////////////
  969. //
  970. //    Drag Manager callback routines which dispatch to a window’s method
  971. //
  972.  
  973. pascal OSErr
  974. CallWindowDragTrackingHandler(DragTrackingMessage dragMessage,WindowRef theWindow,void * /* refCon */,DragReference theDrag)
  975. {
  976.     TWindow *wobj = GetWindowObject(theWindow);
  977.     
  978.     if (wobj)
  979.         return(wobj->HandleDrag(dragMessage,theDrag));
  980.     else
  981.         return dragNotAcceptedErr;
  982. }
  983.  
  984.     
  985. pascal OSErr
  986. CallWindowDragReceiveHandler(WindowRef theWindow,void * /* refCon */,DragReference theDrag)
  987. {
  988.     TWindow *wobj = GetWindowObject(theWindow);
  989.     
  990.     if (wobj)
  991.         return(wobj->HandleDrop(theDrag));
  992.     else
  993.         return dragNotAcceptedErr;
  994. }
  995.  
  996.  
  997.  
  998.  
  999.